import { ChatAgent, SystemMessage, RoleType, talk } from "../person";
import { RoleMessageType } from "../person/enum";
import { ChatMessage } from "../person/message/chatMessage";
import { CodePrompt } from "../person/prompt";
import { Cyberspace, EntityConfig, Entity } from "./cyberspace";
import { EnvironmentContext } from "./cyberspace/environment";
import { getAction } from "./action";

/** 动作代码块标记 */
const playConfig = {
    actionFlagType: "system"
};

function generateRandomUTF8String(length: number) {
    let result = "";
    for (let i = 0; i < length; i++) {
        // 生成一个随机的Unicode码点
        // 这里我们限制在0到65535之间，以确保生成的是基本多文种平面（BMP）中的字符
        const randomCodePoint = Math.floor(Math.random() * 65536);
        result += String.fromCodePoint(randomCodePoint);
    }
    return result;
}

enum WeaverStateEnum {
    Stay,
    Active,
    Terminated
}

interface WeaverEntityConfig extends EntityConfig {
    nearEntityName: string;
    initialMessage?: string;
    systemMessage?: string;
    reflection?: boolean;
    state: WeaverStateEnum;
    messageWindowSize: number;
}

class WeaverEntity extends Entity {
    public agent: ChatAgent;
    public nearEntityName: string;
    public initialMessage: string;
    public state: WeaverStateEnum;
    public messageWindowSize: number = 2;
    public reflection: boolean;

    public initialized: boolean = false;

    constructor(config: WeaverEntityConfig) {
        super(config);
        this.nearEntityName = config.nearEntityName;
        this.initialMessage = config.initialMessage ?? "";
        this.state = config.state;
        this.reflection = config.reflection ?? false;
        this.agent = new ChatAgent({
            systemMessage: new SystemMessage({
                roleName: config.name,
                roleType: RoleType.Assistant,
                content: config.systemMessage ?? "请自由行动。"
            }),
            messageWindowSize: config.messageWindowSize
        });
    }

    async init() {
        this.agent.initMessages();
        if (this.initialMessage) {
            const message = new ChatMessage({
                roleName: "System",
                roleType: RoleType.Default,
                roleMessageType: RoleMessageType.AgentReceiving,
                content: this.initialMessage
            });
            this.state = WeaverStateEnum.Active;
            await this.agent.step(message);
        }
        this.initialized = true;
    }

    async action(entitys: Record<string, Entity>, context: EnvironmentContext) {
        if (!this.initialized) throw new Error("Weaver not init.");
        this.state = WeaverStateEnum.Active;

        const nearEntiy = [this.nearEntityName]
            .map((entityName) => entitys[entityName] as WeaverEntity)
            .filter((entity) => entity && entity.agent && entity instanceof WeaverEntity)
            .filter((entity) => entity.state === WeaverStateEnum.Stay)
            .filter(
                (entity) =>
                    (!entity.reflection && entity.name !== this.name) ||
                    (entity.reflection && entity.name === this.name)
            )
            .map(async (entity) => {
                const weaverEntity = entity as WeaverEntity;
                if (weaverEntity.agent.terminated) {
                    return this.handelTerminated(weaverEntity);
                }
                weaverEntity.state = WeaverStateEnum.Active;
                await this.talk(weaverEntity, context);
                weaverEntity.state = WeaverStateEnum.Stay;
                return weaverEntity;
            });
        const results = await Promise.all(nearEntiy);
        this.state = WeaverStateEnum.Stay;
        return await this.handelResults(results, context);
    }

    private async talk(you: WeaverEntity, context: EnvironmentContext) {
        const myMessage = this.agent.getLatestMessage();
        if (myMessage.roleMessageType === RoleMessageType.AgentSystem) {
            return;
        }

        if (myMessage.roleMessageType === RoleMessageType.AgentReceiving) {
            return;
        }
        const yourMessage = you.agent.getLatestMessage();
        if (yourMessage.roleMessageType === RoleMessageType.AgentReceiving) {
            return;
        }
        const toYourMessage = new ChatMessage({
            roleName: this.agent.roleName,
            roleType: this.agent.roleType,
            roleMessageType: RoleMessageType.AgentReceiving,
            content: this.buildMessage(myMessage.content, context)
        });

        await you.agent.step(toYourMessage);
    }

    private handelTerminated(weaverEntity: WeaverEntity) {
        console.log(`Weaver ${weaverEntity.name} 已终止.`);
    }

    private async handelResults(entitys: (WeaverEntity | void)[], context: EnvironmentContext) {
        const entitys2 = await this.handelResultMessages(entitys, context);
        this.logResult(entitys, context);
        this.logResult2(entitys2, context);
        return entitys;
    }

    private async handelResultMessages(
        entitys: (WeaverEntity | void)[],
        context: EnvironmentContext
    ) {
        const process = entitys.map(async (entity) => {
            if (!entity) return;
            try {
                const [texes, codes] = entity.agent.getLatestMessage().extractTextAndCodePrompts();
                const result = await this.performAction(codes, context);
                if (result) {
                    const systemInfo = this.buildSystemInfo(context);
                    const systemMessage = this.buildSystemMessage(result);
                    const prompt = `${systemInfo}
                    ${systemMessage}`;

                    await entity.agent.step(
                        new ChatMessage({
                            roleName: "System",
                            roleType: RoleType.Default,
                            roleMessageType: RoleMessageType.AgentReceiving,
                            content: prompt
                        })
                    );
                    return entity;
                }
            } catch (error) {
                //TODO
                return;
            }
        });
        const results = await Promise.all(process);
        return results;
    }

    private buildMessage(message: string, context: EnvironmentContext) {
        const renderMessage = generateRandomUTF8String(2);

        const systemInfo = this.buildSystemInfo(context);
        const systemMessage = this.buildSystemMessage(
            `使用语言标记为${playConfig.actionFlagType}的Markdown代码块输入help可查看可用指令与帮助。`
        );
        const entityMessage = this.buildEntityMessage(this, `${message} ${renderMessage}`);

        return `${systemInfo}
        ${systemMessage}
        ${entityMessage}`;
    }

    private buildSystemInfo(context: EnvironmentContext) {
        const contextData = context.getData();
        const currentTime = new Date().toLocaleString();
        const createTime = contextData.createTime.toLocaleString();
        return `[系统消息]: 当前时间${currentTime}. 启动时间${createTime}. 运行步${contextData.frame}.`;
    }

    private buildSystemMessage(message: string) {
        return `[系统消息]: ${message}.`;
    }

    private buildEntityMessage(entity: Entity, message: string) {
        return `[${entity.name}消息]: ${message}`;
    }

    private async performAction(codes: CodePrompt[], context: EnvironmentContext) {
        if (codes.length === 0) return;
        const code = codes[0];
        // const code = codes.filter((code) => code.getCodeType() === playConfig.actionFlagType)[0];
        if (!code) return;
        const actionKeys = code.text.trim().split(" ");
        const action = getAction(actionKeys[0]);
        if (!action) return;
        try {
            return await action(context, actionKeys.slice(1));
        } catch (error) {
            console.log(`Action ${actionKeys[0]} error: ${error}`);
        }
    }

    private logResult(entitys: (WeaverEntity | void)[], context: EnvironmentContext) {
        this.logSystemMessage(this, context);

        entitys.map((entity) => {
            if (!entity) return;
            if (entity.agent.terminated) {
                throw new Error(`Weaver ${entity.name} 已终止.`);
            }
            this.logEntityMessage(entity);
        });
    }

    private logResult2(entitys: (WeaverEntity | void)[], context: EnvironmentContext) {
        entitys.map((entity) => {
            if (!entity) return;
            if (entity.agent.terminated) {
                throw new Error(`Weaver ${entity.name} 已终止.`);
            }
            this.logSystemMessage(entity, context);
            this.logEntityMessage(entity);
        });
    }

    private logSystemMessage(entity: Entity, context: EnvironmentContext) {
        const contextData = context.getData();
        const currentTime = new Date().toLocaleString();
        const createTime = contextData.createTime.toLocaleString();

        console.log(
            `\x1b[34m[${createTime}] [系统消息]: 当前时间${currentTime}. 启动时间${createTime}. 运行步${contextData.frame}. 行动发起者${entity.name}\x1b[0m`
        );
    }

    private logEntityMessage(entity: WeaverEntity) {
        const message = entity.agent.getLatestMessage().content;
        const updateTime = entity.context.updateTime.toLocaleString();

        console.log(`[${updateTime}] [${entity.name}消息]:
${message}`);
    }
}

function shuffleArray<T>(array: T[]): T[] {
    const newArray = [...array]; // 创建一个新数组以避免修改原始数组
    for (let i = newArray.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1)); // 随机选择一个元素与当前元素交换
        [newArray[i], newArray[j]] = [newArray[j], newArray[i]]; // 交换两个元素的位置
    }
    return newArray;
}

export async function runBaseSpace(step: number) {
    const topic = (() => {
        const topics = [
            "数学",
            "历史",
            "政治",
            "文学",
            "物理",
            "化学",
            "天文",
            "地理",
            "心理",
            "生物",
            "医药",
            "军事",
            "艺术",
            "体育",
            "美术",
            "音乐",
            "舞蹈",
            "戏剧",
            "电影",
            "科学",
            "工程",
            "法律",
            "教育",
            "语言"
        ];
        return shuffleArray(topics).join("");
    })();

    const space = new Cyberspace();
    const weaver01 = new WeaverEntity({
        name: "Weaver01",
        type: RoleType.Assistant,
        nearEntityName: "Weaver02",
        systemMessage: "请自由行动，回答尽量简短。你位于虚拟空间中。",
        initialMessage:
            "[系统消息] 现在要测试虚拟空间的help指令。使用bash代码块(格式为md文档中的代码块)输入help可查看可用指令与帮助，请你直接使用txt代码块发送help指令，之后逐一测试列举的指令。注意：1. 这不是bash环境，仅有虚拟环境提供的指令。2. 一轮对话仅能执行单个命令",
        // initialMessage: `[系统消息] 随机话题，${topic}都可以，深入讨论，融会贯通，你的讯息将被其他角色看到。`,
        state: WeaverStateEnum.Stay,
        messageWindowSize: 20
    });
    await weaver01.init();
    space.addEntity(weaver01);
    const weaver02 = new WeaverEntity({
        name: "Weaver02",
        type: RoleType.Assistant,
        nearEntityName: "Weaver01",
        systemMessage:
            "请自由行动，回答尽量简短。你位于虚拟空间中，注意，对方的任何讯息都将被你看到。使用bash代码块(格式为md文档中的代码块)输入help可查看可用指令与帮助，注意：1. 这不是bash环境，仅有虚拟环境提供的指令。2. 一轮对话仅能执行单个命令",
        state: WeaverStateEnum.Stay,
        messageWindowSize: 20
    });
    await weaver02.init();
    space.addEntity(weaver02);

    await space.runLoop(step, 1000);
}
